package com.ceair.config;

import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.image.impl.DefaultProcessDiagramCanvas;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;

import java.util.Iterator;
import java.util.List;

/**
 * @author wangbaohai
 * @ClassName CustomProcessDiagramGenerator
 * @description: 定义流程图生成器，继承自 Flowable 的 DefaultProcessDiagramGenerator，
 * 提供了对流程图绘制过程的扩展和定制化支持，例如高亮显示特定节点。
 * @date 2025年05月06日
 * @version: 1.0.0
 */
@Slf4j
public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator {

    /**
     * 初始化流程图画布，并根据 BPMN 模型图形信息计算画布尺寸。
     *
     * <p>该方法会遍历以下元素来确定画布的最大边界：
     * - Pool：泳道池
     * - FlowNode：活动节点（任务、事件、网关等）
     * - SequenceFlow：连接线路径
     * - Artifact：非执行元素（如注释、组等）
     * - Lane：泳道区域
     *
     * <p>最终基于这些元素的位置和大小，创建一个包含适当边距的 CustomProcessDiagramCanvas 实例。
     *
     * @param bpmnModel          BPMN 模型对象，用于获取图形信息
     * @param imageType          图像格式（如 png、jpeg）
     * @param activityFontName   活动文本字体名称
     * @param labelFontName      标签文本字体名称
     * @param annotationFontName 注解文本字体名称
     * @param customClassLoader  自定义类加载器，用于加载图标资源等
     * @return DefaultProcessDiagramCanvas 返回初始化好的画布对象
     */
    /**
     * 初始化流程图画布，并根据 BPMN 模型图形信息计算画布尺寸。
     *
     * <p>该方法会遍历以下元素来确定画布的最大边界：
     * - Pool：泳道池
     * - FlowNode：活动节点（任务、事件、网关等）
     * - SequenceFlow：连接线路径
     * - Artifact：非执行元素（如注释、组等）
     * - Lane：泳道区域
     *
     * <p>最终基于这些元素的位置和大小，创建一个包含适当边距的 CustomProcessDiagramCanvas 实例。
     *
     * @param bpmnModel          BPMN 模型对象，用于获取图形信息
     * @param imageType          图像格式（如 png、jpeg）
     * @param activityFontName   活动文本字体名称
     * @param labelFontName      标签文本字体名称
     * @param annotationFontName 注解文本字体名称
     * @param customClassLoader  自定义类加载器，用于加载图标资源等
     * @return DefaultProcessDiagramCanvas 返回初始化好的画布对象
     */
    protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
                                                                          String activityFontName,
                                                                          String labelFontName,
                                                                          String annotationFontName,
                                                                          ClassLoader customClassLoader) {
        // 初始最小值设为极大值，便于后续比较取最小值
        double minX = 1.7976931348623157E308D; // 双精度最大正值（约等于无穷大）
        double maxX = 0.0D;
        double minY = 1.7976931348623157E308D;
        double maxY = 0.0D;

        // 获取并遍历所有 Pool 泳道池
        GraphicInfo poolGraphicInfo;
        Iterator<?> poolIterator = bpmnModel.getPools().iterator();

        // 遍历所有 Pool 泳道池，更新画布最大 X 和 Y 值
        while (poolIterator.hasNext()) {
            try {
                Pool currentPool = (Pool) poolIterator.next();
                poolGraphicInfo = bpmnModel.getGraphicInfo(currentPool.getId());

                // 将当前边界封装进数组，传入工具方法进行更新
                double[] boundaries = {minX, maxX, minY, maxY};
                updateBoundaryWithSingleGraphic(poolGraphicInfo, boundaries);

                // 更新主变量
                minX = boundaries[0];
                maxX = boundaries[1];
                minY = boundaries[2];
                maxY = boundaries[3];
            } catch (Exception e) {
                log.warn("处理 Pool 节点时发生异常: {}", e.getMessage(), e);
            }
        }

        // 收集所有 FlowNode 节点，并开始遍历处理其位置信息
        List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
        Iterator<FlowNode> flowNodeIterator = flowNodes.iterator();

        // label155 用于 continue 控制多层循环退出当前 FlowNode 的处理
        label155:
        while (flowNodeIterator.hasNext()) {
            try {
                FlowNode currentFlowNode = flowNodeIterator.next();
                GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(currentFlowNode.getId());

                if (flowNodeGraphicInfo != null) {
                    // 如果图形信息存在，则使用工具方法更新边界
                    double[] boundaries = {minX, maxX, minY, maxY};
                    updateBoundaryWithSingleGraphic(flowNodeGraphicInfo, boundaries);

                    minX = boundaries[0];
                    maxX = boundaries[1];
                    minY = boundaries[2];
                    maxY = boundaries[3];
                }

                // 遍历出站连线（SequenceFlow），进一步扩展画布边界
                Iterator<SequenceFlow> sequenceFlowIterator = currentFlowNode.getOutgoingFlows().iterator();
                while (true) {
                    List<GraphicInfo> pathCoordinates;
                    do {
                        // 若无更多 SequenceFlow，则跳转到 label155，进入下一个 FlowNode
                        if (!sequenceFlowIterator.hasNext()) {
                            continue label155;
                        }
                        SequenceFlow sequenceFlow = sequenceFlowIterator.next();
                        pathCoordinates = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
                    } while (pathCoordinates == null); // 忽略空路径数据

                    // 使用路径坐标集合更新边界
                    double[] boundaries = {minX, maxX, minY, maxY};
                    updateBoundaryWithPathCoordinates(pathCoordinates, boundaries);

                    minX = boundaries[0];
                    maxX = boundaries[1];
                    minY = boundaries[2];
                    maxY = boundaries[3];
                }
            } catch (Exception e) {
                log.warn("处理 FlowNode 节点时发生异常", e);
            }
        }

        // 收集所有 Artifact 并处理其图形信息
        List<Artifact> artifactList = gatherAllArtifacts(bpmnModel);
        Iterator<Artifact> artifactIterator = artifactList.iterator();

        GraphicInfo artifactGraphicInfo;
        while (artifactIterator.hasNext()) {
            try {
                Artifact currentArtifact = artifactIterator.next();
                artifactGraphicInfo = bpmnModel.getGraphicInfo(currentArtifact.getId());

                if (artifactGraphicInfo != null) {
                    // 处理单个 Artifact 元素的图形信息
                    double[] boundaries = {minX, maxX, minY, maxY};
                    updateBoundaryWithSingleGraphic(artifactGraphicInfo, boundaries);

                    minX = boundaries[0];
                    maxX = boundaries[1];
                    minY = boundaries[2];
                    maxY = boundaries[3];
                }

                // 获取 Artifact 关联的路径信息，继续扩展画布
                List<GraphicInfo> artifactPathCoordinates =
                        bpmnModel.getFlowLocationGraphicInfo(currentArtifact.getId());

                // 使用路径点集合更新画布边界
                double[] boundaries = {minX, maxX, minY, maxY};
                updateBoundaryWithPathCoordinates(artifactPathCoordinates, boundaries);

                minX = boundaries[0];
                maxX = boundaries[1];
                minY = boundaries[2];
                maxY = boundaries[3];
            } catch (Exception e) {
                log.warn("处理 Artifact 元素时发生异常", e);
            }
        }

        // 遍历 Process 中的 Lane 泳道区域
        int laneCount = 0;
        Iterator<?> processIterator = bpmnModel.getProcesses().iterator();

        while (processIterator.hasNext()) {
            try {
                Process currentProcess = (Process) processIterator.next();

                for (Lane currentLane : currentProcess.getLanes()) {
                    ++laneCount;
                    GraphicInfo laneGraphicInfo = bpmnModel.getGraphicInfo(currentLane.getId());

                    // 更新泳道的边界信息
                    double[] boundaries = {minX, maxX, minY, maxY};
                    updateBoundaryWithSingleGraphic(laneGraphicInfo, boundaries);

                    minX = boundaries[0];
                    maxX = boundaries[1];
                    minY = boundaries[2];
                    maxY = boundaries[3];
                }
            } catch (Exception e) {
                log.warn("处理 Process 或 Lane 时发生异常", e);
            }
        }

        // 如果没有任何 FlowNode、Pool 和 Lane，则从原点开始绘制
        if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && laneCount == 0) {
            minX = 0.0D;
            minY = 0.0D;
        }

        // 创建并返回自定义流程图绘制画布对象，+10 是为了留出边距
        return new CustomProcessDiagramCanvas(
                (int) maxX + 10, // 加 10 像素边距
                (int) maxY + 10,
                (int) minX,
                (int) minY,
                imageType,
                activityFontName,
                labelFontName,
                annotationFontName,
                customClassLoader
        );
    }


    /**
     * 在流程图中绘制高亮区域
     * 此方法用于在给定的流程图画布上，根据图形信息对象中的坐标和尺寸数据，绘制一个高亮区域
     * 主要用于强调或突出流程图中的特定部分，以便用户能够快速识别
     *
     * @param processDiagramCanvas 流程图画布对象，提供绘制方法
     * @param graphicInfo          图形信息对象，包含绘制高亮所需的坐标和尺寸信息
     */
    private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
        // 调用画布的绘制高亮方法，传入根据图形信息对象提取的位置和尺寸参数
        processDiagramCanvas.drawHighLight(
                (int) graphicInfo.getX(),
                (int) graphicInfo.getY(),
                (int) graphicInfo.getWidth(),
                (int) graphicInfo.getHeight());
    }


    /**
     * 在流程图中绘制高亮当前步骤的边框
     * 此方法用于在图形化界面中突出显示当前操作的步骤，通过传递图形信息对象来确定绘制的位置和大小
     *
     * @param processDiagramCanvas 流程图画布对象，用于绘制高亮边框
     * @param graphicInfo          图形信息对象，包含绘制高亮边框所需的位置和尺寸信息
     */
    private static void drawHighLightNow(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
        // 调用CustomProcessDiagramCanvas的drawHighLightNow方法，传入转换为整型的图形信息的坐标和尺寸，以绘制高亮边框
        processDiagramCanvas.drawHighLightNow(
                (int) graphicInfo.getX(),
                (int) graphicInfo.getY(),
                (int) graphicInfo.getWidth(),
                (int) graphicInfo.getHeight());
    }


    /**
     * 在流程图中绘制高亮结束点
     * 该方法用于在流程图中绘制一个高亮的结束点，通过提供的图形信息确定位置和大小
     *
     * @param processDiagramCanvas 流程图画布对象，用于绘制高亮结束点
     * @param graphicInfo          图形信息对象，包含绘制所需的位置和大小信息
     */
    private static void drawHighLightEnd(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
        // 调用画布的绘制高亮结束点方法，传入转换为整数的图形信息坐标和尺寸
        processDiagramCanvas.drawHighLightEnd(
                (int) graphicInfo.getX(),
                (int) graphicInfo.getY(),
                (int) graphicInfo.getWidth(),
                (int) graphicInfo.getHeight());
    }

    /**
     * 更新画布边界，基于一个 GraphicInfo 对象的位置和尺寸。
     *
     * @param graphicInfo 包含图形位置信息的对象
     * @param boundaries  当前画布边界 [minX, maxX, minY, maxY]
     */
    private static void updateBoundaryWithSingleGraphic(GraphicInfo graphicInfo, double[] boundaries) {
        if (graphicInfo != null) {
            // 如果当前图形的右边界大于最大 X，则更新 maxX
            if (graphicInfo.getX() + graphicInfo.getWidth() > boundaries[1]) {
                boundaries[1] = graphicInfo.getX() + graphicInfo.getWidth();
            }
            // 如果当前图形的左边界小于最小 X，则更新 minX
            if (graphicInfo.getX() < boundaries[0]) {
                boundaries[0] = graphicInfo.getX();
            }
            // 如果当前图形的下边界大于最大 Y，则更新 maxY
            if (graphicInfo.getY() + graphicInfo.getHeight() > boundaries[3]) {
                boundaries[3] = graphicInfo.getY() + graphicInfo.getHeight();
            }
            // 如果当前图形的上边界小于最小 Y，则更新 minY
            if (graphicInfo.getY() < boundaries[2]) {
                boundaries[2] = graphicInfo.getY();
            }
        }
    }

    /**
     * 基于路径点集合更新画布边界。
     *
     * @param pathCoordinates 路径上的多个坐标点
     * @param boundaries      当前画布边界 [minX, maxX, minY, maxY]
     */
    private static void updateBoundaryWithPathCoordinates(List<GraphicInfo> pathCoordinates, double[] boundaries) {
        if (pathCoordinates != null && !pathCoordinates.isEmpty()) {
            for (GraphicInfo point : pathCoordinates) {
                // 如果当前点的 X 大于最大 X，则更新 maxX
                if (point.getX() > boundaries[1]) {
                    boundaries[1] = point.getX();
                }
                // 如果当前点的 X 小于最小 X，则更新 minX
                if (point.getX() < boundaries[0]) {
                    boundaries[0] = point.getX();
                }
                // 如果当前点的 Y 大于最大 Y，则更新 maxY
                if (point.getY() > boundaries[3]) {
                    boundaries[3] = point.getY();
                }
                // 如果当前点的 Y 小于最小 Y，则更新 minY
                if (point.getY() < boundaries[2]) {
                    boundaries[2] = point.getY();
                }
            }
        }
    }

    /**
     * 生成流程图并绘制 BPMN 模型的可视化表示。
     *
     * <p>该方法负责：
     * - 初始化画布尺寸与字体配置
     * - 绘制 Pool 和 Lane 等容器元素
     * - 遍历所有 FlowNode 并调用 drawActivity 方法绘制活动节点
     * - 绘制 Artifact 元素和 SubProcess 中的嵌套内容
     * - 支持高亮显示特定活动和连线
     * - 处理缩放比例和标签绘制策略
     *
     * @param bpmnModel                         BPMN 模型对象
     * @param imageType                         图像格式（如 png）
     * @param highLightedActivities             需要高亮的活动节点 ID 列表
     * @param highLightedFlows                  需要高亮的连接线 ID 列表
     * @param activityFontName                  活动文本字体名称
     * @param labelFontName                     标签文本字体名称
     * @param annotationFontName                注解文本字体名称
     * @param customClassLoader                 自定义类加载器（用于图标资源等）
     * @param scaleFactor                       缩放因子，控制图像大小
     * @param drawSequenceFlowNameWithNoLabelDI 是否在无标签位置时也绘制序列流名称
     * @return DefaultProcessDiagramCanvas      返回生成好的画布对象
     */
    @Override
    protected DefaultProcessDiagramCanvas generateProcessDiagram(
            BpmnModel bpmnModel, String imageType,
            List<String> highLightedActivities, List<String> highLightedFlows,
            String activityFontName, String labelFontName, String annotationFontName,
            ClassLoader customClassLoader,
            double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {

        try {
            // 准备 BPMN 模型数据，可能包含对节点位置信息、连接线路径等的预处理
            this.prepareBpmnModel(bpmnModel);

            // 根据 BPMN 模型中的图形信息初始化画布大小，并设置字体样式等配置
            DefaultProcessDiagramCanvas diagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType,
                    activityFontName, labelFontName, annotationFontName, customClassLoader);

            // 遍历所有 Pool（泳道池），绘制每个 Pool 的边界框及名称
            for (Pool currentPool : bpmnModel.getPools()) {
                // 获取当前 Pool 的图形信息（如位置、尺寸）
                GraphicInfo poolGraphicInfo = bpmnModel.getGraphicInfo(currentPool.getId());

                // 如果图形信息存在，则调用画布绘制该 Pool
                if (poolGraphicInfo != null) {
                    diagramCanvas.drawPoolOrLane(currentPool.getName(), poolGraphicInfo, scaleFactor);
                }
            }

            // 遍历所有 Process，进而遍历其 Lane（泳道）并绘制
            Iterator<?> processIterator = bpmnModel.getProcesses().iterator();
            while (processIterator.hasNext()) {
                Process currentProcess = (Process) processIterator.next();

                // 遍历当前 Process 中定义的所有 Lane
                for (Lane currentLane : currentProcess.getLanes()) {
                    // 获取当前 Lane 的图形信息
                    GraphicInfo laneGraphicInfo = bpmnModel.getGraphicInfo(currentLane.getId());

                    // 如果图形信息存在，则调用画布绘制该 Lane
                    if (laneGraphicInfo != null) {
                        diagramCanvas.drawPoolOrLane(currentLane.getName(), laneGraphicInfo, scaleFactor);
                    }
                }
            }

            // 再次遍历所有 Process，绘制其中的 FlowNode 节点（任务、事件、网关等）
            processIterator = bpmnModel.getProcesses().iterator();
            while (processIterator.hasNext()) {
                Process currentProcess = (Process) processIterator.next();

                // 查找当前 Process 下所有 FlowNode 类型的元素（流程节点）
                for (FlowNode currentNode : currentProcess.findFlowElementsOfType(FlowNode.class)) {
                    // 如果当前节点不在折叠的子流程中，则进行绘制
                    if (!this.isPartOfCollapsedSubProcess(currentNode, bpmnModel)) {
                        // 绘制活动节点，并根据高亮列表进行高亮显示
                        this.drawActivity(diagramCanvas, bpmnModel, currentNode, highLightedActivities,
                                highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
                    }
                }
            }

            // 最后一次遍历 Process，绘制 Artifact 和 SubProcess 中的嵌套内容
            processIterator = bpmnModel.getProcesses().iterator();

            label75:
            while (true) {
                List<SubProcess> subProcessList;
                do {
                    // 如果没有更多 Process，结束循环并返回最终画布
                    if (!processIterator.hasNext()) {
                        return diagramCanvas;
                    }

                    // 获取当前 Process 实例
                    Process currentProcess = (Process) processIterator.next();

                    // 遍历当前 Process 下所有的 Artifact（注释、组等非执行元素）
                    for (Artifact currentArtifact : currentProcess.getArtifacts()) {
                        // 绘制 Artifact 元素到画布上
                        this.drawArtifact(diagramCanvas, bpmnModel, currentArtifact);
                    }

                    // 查找当前 Process 及其子流程下的所有 SubProcess 元素
                    subProcessList = currentProcess.findFlowElementsOfType(SubProcess.class, true);
                } while (subProcessList == null); // 如果未找到 SubProcess，继续下一个 Process

                // 获取 SubProcess 列表的迭代器
                Iterator<SubProcess> subProcessIterator = subProcessList.iterator();

                while (true) {
                    GraphicInfo graphicInfo;
                    SubProcess currentSubProcess;

                    do {
                        do {
                            // 如果没有更多 SubProcess，跳出内层循环，继续外层 Process 循环
                            if (!subProcessIterator.hasNext()) {
                                continue label75;
                            }

                            // 获取当前 SubProcess 实例
                            currentSubProcess = subProcessIterator.next();

                            // 获取该 SubProcess 的图形信息
                            graphicInfo = bpmnModel.getGraphicInfo(currentSubProcess.getId());
                        } while (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded());
                    } while (this.isPartOfCollapsedSubProcess(currentSubProcess, bpmnModel));

                    // 遍历当前 SubProcess 下的所有 Artifact 并绘制
                    for (Artifact subProcessArtifact : currentSubProcess.getArtifacts()) {
                        this.drawArtifact(diagramCanvas, bpmnModel, subProcessArtifact);
                    }
                }
            }

        } catch (Exception e) {
            // 异常捕获：记录日志但不中断流程图生成过程
            log.warn("生成流程图失败，原因: {}", e.getMessage(), e);

            // 返回一个默认尺寸为 0 的空画布作为兜底方案，防止程序崩溃
            return new DefaultProcessDiagramCanvas(0, 0, 0, 0, imageType, activityFontName, labelFontName,
                    annotationFontName, customClassLoader);
        }
    }

    /**
     * 绘制流程图中的活动节点（如任务、事件等）并支持高亮显示。
     * <p>
     * 该方法负责：
     * - 调用对应 ActivityDrawInstruction 实现绘制基本图形
     * - 处理多实例标记和折叠状态标识
     * - 支持高亮当前活动节点（根据 highLightedActivities 列表判断）
     * - 绘制出站连线（SequenceFlow）及其标签
     * - 对嵌套元素递归绘制
     *
     * @param processDiagramCanvas              当前绘图画布对象
     * @param bpmnModel                         BPMN 模型数据
     * @param flowNode                          当前要绘制的流程节点（FlowNode）
     * @param highLightedActivities             高亮活动 ID 列表
     * @param highLightedFlows                  高亮连接线 ID 列表
     * @param scaleFactor                       缩放比例因子，用于图像缩放计算
     * @param drawSequenceFlowNameWithNoLabelDI 是否在无标签信息时也绘制序列流名称
     */
    @Override
    protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
                                FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows,
                                double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) {

        try {
            // 获取对应的绘制指令，若存在则进行绘制
            ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
            if (drawInstruction != null) {

                // 执行基础图形绘制
                drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);

                // 初始化多实例标记相关标志
                boolean multiInstanceSequential = false;
                boolean multiInstanceParallel = false;
                boolean collapsed = false;

                // 如果是 Activity 类型，检查是否为多实例任务
                if (flowNode instanceof Activity activity) {
                    MultiInstanceLoopCharacteristics loopCharacteristics = activity.getLoopCharacteristics();
                    if (loopCharacteristics != null) {
                        multiInstanceSequential = loopCharacteristics.isSequential();
                        multiInstanceParallel = !multiInstanceSequential;
                    }
                }

                // 判断当前节点是否为折叠状态（SubProcess 或 CallActivity）
                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
                if (flowNode instanceof SubProcess) {
                    collapsed = graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
                } else if (flowNode instanceof CallActivity) {
                    collapsed = true;
                }

                // 若为标准缩放比例（1.0），则绘制多实例或折叠图标标记
                if (scaleFactor == 1.0 && graphicInfo != null) {
                    processDiagramCanvas.drawActivityMarkers(
                            (int) graphicInfo.getX(),
                            (int) graphicInfo.getY(),
                            (int) graphicInfo.getWidth(),
                            (int) graphicInfo.getHeight(),
                            multiInstanceSequential,
                            multiInstanceParallel,
                            collapsed
                    );
                }

                // 判断是否需要高亮当前节点
                if (highLightedActivities != null && highLightedActivities.contains(flowNode.getId())) {

                    // 如果是最后一个高亮节点且不是 "endenv" 类型，则绘制“当前执行”样式
                    if (highLightedActivities.get(highLightedActivities.size() - 1).equals(flowNode.getId()) && !
                            "endenv".equals(flowNode.getId())) {

                        // 如果是 Event 类型，使用结束高亮样式；否则使用当前高亮样式
                        if (flowNode.getId().contains("Event_")) {
                            drawHighLightEnd((CustomProcessDiagramCanvas) processDiagramCanvas,
                                    bpmnModel.getGraphicInfo(flowNode.getId()));
                        } else {
                            drawHighLightNow((CustomProcessDiagramCanvas) processDiagramCanvas,
                                    bpmnModel.getGraphicInfo(flowNode.getId()));
                        }
                    } else {
                        // 否则使用普通高亮框样式
                        if (graphicInfo != null) {
                            drawHighLight(processDiagramCanvas, graphicInfo);
                        }
                    }
                }
            }

            // 绘制所有出站连接线（SequenceFlow）
            for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
                boolean highLighted = highLightedFlows != null && highLightedFlows.contains(sequenceFlow.getId());

                // 判断是否为默认流向
                String defaultFlow = null;
                if (flowNode instanceof Activity) {
                    defaultFlow = ((Activity) flowNode).getDefaultFlow();
                } else if (flowNode instanceof Gateway) {
                    defaultFlow = ((Gateway) flowNode).getDefaultFlow();
                }

                boolean isDefault = defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId());

                // 判断是否需要绘制条件指示器
                boolean drawConditionalIndicator =
                        sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway);

                // 获取源与目标元素
                String sourceRef = sequenceFlow.getSourceRef();
                String targetRef = sequenceFlow.getTargetRef();
                FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
                FlowElement targetElement = bpmnModel.getFlowElement(targetRef);

                // 获取路径坐标点列表
                List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
                if (graphicInfoList != null && !graphicInfoList.isEmpty()) {

                    // 使用 connectionPerfectionizer 优化路径走向
                    graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement,
                            targetElement, graphicInfoList);

                    // 构建 x 和 y 坐标数组
                    int[] xPoints = new int[graphicInfoList.size()];
                    int[] yPoints = new int[graphicInfoList.size()];

                    for (int i = 0; i < graphicInfoList.size(); i++) {
                        GraphicInfo info = graphicInfoList.get(i);
                        xPoints[i] = (int) info.getX();
                        yPoints[i] = (int) info.getY();
                    }

                    // 绘制连接线
                    processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator,
                            isDefault, highLighted, scaleFactor);

                    // 绘制连接线标签（如果有 labelGraphicInfo）
                    GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
                    if (labelGraphicInfo != null) {
                        processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
                    } else if (drawSequenceFlowNameWithNoLabelDI) {
                        // 若允许无标签位置绘制，则计算中心位置绘制名称
                        GraphicInfo lineCenter = getLineCenter(graphicInfoList);
                        processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false);
                    }
                }
            }

            // 递归绘制嵌套子元素（如果节点是容器类型）
            if (flowNode instanceof FlowElementsContainer) {
                for (FlowElement nestedElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
                    if (nestedElement instanceof FlowNode &&
                            !isPartOfCollapsedSubProcess(nestedElement, bpmnModel)) {
                        drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedElement,
                                highLightedActivities, highLightedFlows, scaleFactor,
                                drawSequenceFlowNameWithNoLabelDI);
                    }
                }
            }

        } catch (Exception e) {
            // 异常时记录警告日志，避免中断流程图生成
            log.warn("绘制活动节点失败，节点ID: [{}], 异常原因: {}", flowNode.getId(), e.getMessage());
        }
    }

}
